home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari Mega Archive 1
/
Atari Mega Archive - Volume 1.iso
/
language
/
pcl_src.zoo
/
user-instances.lsp
< prev
next >
Wrap
Text File
|
1992-09-03
|
29KB
|
685 lines
;;;-*-Mode:LISP; Package: PCL; Base:10; Syntax:Common-lisp; -*-
;;;
;;; *************************************************************************
;;;
;;; File: user-instances.lisp.
;;;
;;; by Trent E. Lange, Effective Date 06-02-92
;;;
;;;
;;; This file contains a metaclass (User-Vector-Class) whose instances
;;; are stored as simple-vectors, saving space over PCL's standard instance
;;; representations of PCL at the cost of some class redefinition flexibiliity.
;;;
;;; Permission is granted to any individual or institution to use, copy,
;;; modify and distribute this document.
;;;
;;; Suggestions, bugs, criticism and questions to lange@cs.ucla.edu
;;; *************************************************************************
;;;
(in-package 'pcl)
;;; This file builds on the PCL-USER-INSTANCES feature of July 92 PCL
;;; to define the USER-VECTOR-CLASS metaclass whose instances are simple
;;; vectors. The first element of the instance vector is the instance's
;;; class wrapper (providing internal PCL information about the instance's
;;; class). The remaining elements of the instance vector are the instance's
;;; slots themselves.
;;;
;;; The space overhead of user-vector-instances is only two vector cells
;;; (one for the vector, one for the wrapper). This is contrast to standard
;;; PCL instances, which have a total overhead of four cells. (Standard
;;; instances in PCL are represented as instances of structure STD-INSTANCE
;;; having two slots, one for the wrapper and one holding a simple-vector
;;; which is the instance's slots). This two-cell space savings per instance
;;; comes at the cost of losing some class redefinition flexibility, since
;;; simple-vectors cannot have their sizes changed dynamically.
;;; All current instances of user-instance-vectors therefore become
;;; permanently obsolete if the classes' instance slots change.
;;;
;;; This code requires July 92 PCL or later compiled with the
;;; PCL-USER-INSTANCES feature turned on (see PCL's low.lisp file).
;;;
#-pcl-user-instances
(eval-when (compile load eval)
(error "Cannot use user-instances, since PCL was compiled without
PCL-USER-INSTANCES on the *features* list (see pcl file low.lisp.)")
)
(eval-when (compile load eval)
(defclass user-vector-class-mixin () ()
(:documentation
"Use this mixin for metaclasses whose instances are USER-INSTANCES
instantiated as simple-vectors. This saves space over the standard
instances used by standard-class, at the cost of losing the ability to
redefine the slots in a class and still have old instances updated correctly."))
(defclass user-vector-class (user-vector-class-mixin standard-class) ()
(:documentation
"A metaclass whose instances are USER-INSTANCES instantiated as simple-vectors.
This saves space over the standard instances used by standard-class, at the
cost of losing the ability to redefine the slots in a class and still have old
instances updated correctly."))
(defmethod validate-superclass ((class user-vector-class-mixin)
(new-super T))
(or (typep new-super 'user-vector-class-mixin)
(eq new-super (find-class 'standard-object))))
(defclass user-vector-object (standard-object) ()
(:metaclass user-vector-class))
)
;;;
;;;
;;; Instance allocation stuff.
;;;
(defmacro user-vector-instance-p (object)
(once-only (object)
`(the boolean
(and (simple-vector-p ,object)
(plusp (length (the simple-vector ,object)))
(wrapper-p (%svref ,object 0))))))
(defmacro user-vector-instance-wrapper (object)
`(%svref ,object 0))
(defsetf user-vector-instance-wrapper (object) (new-value)
`(setf (%svref ,object 0) ,new-value))
(defmacro user-vector-instance-slots (instance)
;; The slots vector of user-vector instances is the instance itself.
instance)
(defmacro set-user-vector-instance-slots (instance new-value)
`(progn
(warn "Attempt to set user-vector-instance-slots of ~S to ~S"
,instance ,new-value)
,new-value))
(defun user-instance-p (x)
"Is X a user instance, specifically a user-vector-instance?"
(user-vector-instance-p x))
(defun user-instance-slots (x)
"Return the slots of this user-vector-instance."
(user-vector-instance-slots x))
(defun user-instance-wrapper (x)
"Return the wrapper of this user-vector-instance."
(user-vector-instance-wrapper x))
(defun set-user-instance-wrapper (x new)
(setf (user-vector-instance-wrapper x) new))
(defmacro get-user-instance-p (x)
`(user-vector-instance-p ,x))
(defmacro get-user-instance-wrapper (x)
`(user-vector-instance-wrapper ,x))
(defmacro get-user-instance-slots (x)
`(user-vector-instance-slots ,x))
(eval-when (eval #+cmu load)
(force-compile 'user-instance-p)
(force-compile 'user-instance-slots)
(force-compile 'user-instance-wrapper)
(force-compile 'set-user-instance-wrapper))
;;;
;;; Methods needed for user-vector-class-mixin.
;;;
(defconstant *not-a-slot* (gensym "NOT-A-SLOT"))
(defmethod allocate-instance ((class user-vector-class-mixin) &rest initargs)
(declare (ignore initargs))
(unless (class-finalized-p class) (finalize-inheritance class))
(let* ((class-wrapper (class-wrapper class))
(copy-instance (wrapper-allocate-static-slot-storage-copy
class-wrapper))
(instance (copy-simple-vector copy-instance)))
(declare (type simple-vector copy-instance instance))
(setf (user-vector-instance-wrapper instance) class-wrapper)
instance))
(defmethod make-instances-obsolete ((class user-vector-class-mixin))
"The slots of user-vector-instances are stored in the instance vector
themselves (a simple-vector), so old instances cannot be updated properly."
(setf (slot-value class 'prototype) NIL)
(warn "Obsoleting user-vector class ~A, all current instances will be invalid..."
class))
(defmethod compute-layout :around ((class user-vector-class-mixin)
cpl instance-eslotds)
;; First element of user-vector-instance is actually its wrapper.
(declare (ignore cpl instance-eslotds))
(cons *not-a-slot* (call-next-method)))
(defmethod compute-instance-layout :around ((class user-vector-class-mixin)
instance-eslotds)
;; First element of user-vector-instance is actually its wrapper.
(declare (ignore instance-eslotds))
(cons *not-a-slot* (call-next-method)))
(defmethod wrapper-fetcher ((class user-vector-class-mixin))
'user-vector-instance-wrapper)
(defmethod slots-fetcher ((class user-vector-class-mixin))
'user-vector-instance-slots)
(defmethod raw-instance-allocator ((class user-vector-class-mixin))
'allocate-user-vector-instance)
;;; Inform PCL that it is still safe to use its standard slot-value
;;; optimizations with user-vector-class-mixin's slot-value-using-class
;;; methods:
(pushnew
'(user-vector-class-mixin standard-object standard-effective-slot-definition)
*safe-slot-value-using-class-specializers*)
(pushnew
'(T user-vector-class-mixin standard-object standard-effective-slot-definition)
*safe-set-slot-value-using-class-specializers*)
(pushnew
'(user-vector-class-mixin standard-object standard-effective-slot-definition)
*safe-slot-boundp-using-class-specializers*)
(defmethod slot-value-using-class
((class user-vector-class-mixin)
(object standard-object)
(slotd standard-effective-slot-definition))
(let* ((location (slot-definition-location slotd))
(value
(typecase location
(fixnum
(%svref (user-vector-instance-slots object) location))
(cons
(cdr location))
(t
(error
"The slot ~s has neither :instance nor :class allocation, ~@
so it can't be read by the default ~s method."
slotd 'slot-value-using-class)))))
(if (eq value *slot-unbound*)